#include "StdAfx.h"
#include "TaxiAgent.h"
#include <algorithm>
#include "math.h"

int IntelliDist(CNode* n1, CNode* n2);

CTaxiAgent::CTaxiAgent(int id, CNode* node, COLORREF color, CEnv* env) 
    : CCarAgent(id, node, ETYPE_TAXI)
{
    m_fare = NULL;
    m_path = NULL;
    m_hasJob = false;
    m_onJob = false;
    m_dijk = new CDijkstras(env->GetNodes(), &IntelliDist);
    m_color = color;

    m_cash = 0.0;
    m_faresCompleted = 0;
    m_birth = CSysTime::Now();
    m_profitRate = 0;

    CString file;
    file.Format("taxi_%d.log", id);
    if (!m_log.Open(file, CFile::modeCreate | CFile::modeReadWrite))
    {
        TRACE("Error opening log file: %s\n", file);
        ASSERT(FALSE);
    }

    m_log.WriteString("t,fares,cash,profitRate\n");
}

CTaxiAgent::~CTaxiAgent(void)
{
    delete m_dijk;
}

bool CTaxiAgent::Step(CEnv* env, int ms)
{
    bool onPath = __super::Step(env, ms);

    if (!onPath)
    {
        if (m_onJob)
        {
            JobComplete(env);
        }

        if (!m_hasJob)
        {
            if (!GetNextJob(env))
            {
                return false;
            }
        }
        else
        {
            StartJob(env);
        }
    }
    else
    {
        // Find a better path
        
        if (m_status == ESTATUS_STOPPED && m_fare)
        {
            if (!m_onJob)
            {
                if (m_node != m_fare->m_start)
                {
                    if (m_path) delete m_path;
                    SetPath(m_dijk->GetPath(m_node, m_fare->m_start));
                }
            }
            else
            {
                if (m_path) delete m_path;
                SetPath(m_dijk->GetPath(m_node, m_fare->m_end));
            }
        }
    }

    if (m_cash == 0)
        m_profitRate = 0;
    else
        m_profitRate = m_cash / ((CSysTime::Now().GetSeconds() - m_birth.GetSeconds()) / 60.0);
    CString line;
    line.Format("%d,%d,%.2f,%.2f\n", m_steps * ms, m_faresCompleted, m_cash,
        m_profitRate);
    m_log.WriteString(line);

    return true;
}

int IntelliDist(CNode* n1, CNode* n2)
{
    CPoint& pt1 = n1->m_pt;
    CPoint& pt2 = n2->m_pt;
    int pixelDist =  n1->GetDistance(n2);

    int traffic = 0;
    if (n2->m_pt.x - n1->m_pt.x > 0)
        traffic = n1->m_trafE;
    else if (n2->m_pt.x - n1->m_pt.x < 0)
        traffic = n1->m_trafW;
    else if (n2->m_pt.y - n1->m_pt.y > 0)
        traffic = n1->m_trafS;
    else if (n2->m_pt.y - n1->m_pt.y < 0)
        traffic = n1->m_trafN;

    return pixelDist + 25*traffic;
}

void CTaxiAgent::JobComplete(CEnv* env)
{
    // Incriment statistics
    m_cash += m_fare->GetCharge();
    m_faresCompleted++;    

    // Find and delete the completed fare
    CFarePtrVec* fares = env->GetFares();
    CFarePtrVecIter it = std::find(fares->begin(), fares->end(), m_fare);
    fares->erase(it);
    delete m_fare;
    m_fare = NULL;
    delete m_fare;
    m_fare = NULL;

    delete m_path;
    m_path = NULL;

    // Set status
    m_onJob = false;
    m_hasJob = false;

}

bool CTaxiAgent::GetNextJob(CEnv* env)
{
    m_fare = env->GetClosestFare(m_node);
    if (m_fare == NULL)
    {
        return false;
    }
    
    m_fare->Start();
    m_hasJob = true;
    m_onJob = false;
    
    // Get path to start
    if (m_node != m_fare->m_start)
    {
        CPath* path = m_dijk->GetPath(m_node, m_fare->m_start);
        SetPath( path );
    }

    return true;
}

void CTaxiAgent::StartJob(CEnv* env)
{    
    // Set path from start to end of job
    CPath* path = m_dijk->GetPath(m_node, m_fare->m_end);
    if (m_path) delete m_path;
    SetPath(path);
    m_onJob = true;
}